package me.zhengjie.domain;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.config.RegisterAddressConfig;
import me.zhengjie.dto.LamInfo;
import me.zhengjie.dto.MesMessage;
import me.zhengjie.dto.sqlServer.*;
import me.zhengjie.modbusTCP.LayUpTCP;
import me.zhengjie.modbusTCP.NoThreeLayUpTcp;
import me.zhengjie.modbusTCP.NoTwoLayUpTCP;
import me.zhengjie.repository.*;
import me.zhengjie.util.LoginUtil;
import me.zhengjie.util.UniqueCodeUtil;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Component
@RequiredArgsConstructor
@Transactional
public class LayUpService {

    private final PalletRepository palletRepository;
    private final ProductionStationRepository productionStationRepository;
    private final ProcesscardRepository processcardRepository;
    private final ProductionInfoRepository productionInfoRepository;
    private final PressRecipesRepository pressRecipesRepository;
    private final LayUpTCP layUpTCP;
    private final NoTwoLayUpTCP noTwoLayUpTCP;
    private final NoThreeLayUpTcp noThreeLayUpTcp;

    /**
     * 扫描工艺卡，绑定工位和工艺卡，向MES发送工艺卡Id，
     * @param processCardCode 工艺卡Id
     * @return 返回工艺卡
     */
    @Transactional
    public MesMessage ScanProcesscard(String processCardCode,String stationCode){
        try {
            String userName = LoginUtil.getLoginUser();
            if (processCardCode.startsWith("-")) {
                processCardCode = "  ".concat(processCardCode);
            }
//            else {
//                int index = processCardCode.indexOf("-");
//                String afterCut = processCardCode.substring(index);
//                processCardCode = "  ".concat(afterCut);
//            }

            /* mesMessage.setLayUpPicture(new FileInputStream("G:\\download\\yxk33g.jpg"));*/

            MesMessage mesMessage = new MesMessage();
            Processcard processcard;

            /*Processcard oldProcesscard = processcardRepository.findByProcesscardCode(processCardCode);
            if (ObjectUtil.isEmpty(oldProcesscard)) {
                // 在数据库查找有没有该工艺卡信息
                LamInfo lamInfo = getProcessCardFromMes(processCardCode, userName);
                if (lamInfo.getStatus_code() == 200) {
                    processcard = getProcesscard(lamInfo);
                    if (Objects.equals(processcard,oldProcesscard)){
                        String layerName = processcard.getLayerName();
                        if (ObjectUtil.isEmpty(pressRecipesRepository.findByLamProgram(layerName))) {
                            log.error("没有找到压机资料，压机程式名称：{}", layerName);
                            mesMessage.setSuccessCode(400);
                            mesMessage.setErrorMessage("没有找到压机资料!");
                            return mesMessage;
                        }
                        // 没有批次号信息
                        processcardRepository.saveAndFlush(processcard);
                        processcard = processcardRepository.findByProcesscardCode(processCardCode);
                    } else {

                    }

                } else {
                    mesMessage.setSuccessCode(400);
                    mesMessage.setErrorMessage("没有找到该批次号的信息");
                    return mesMessage;
                }
            } else {
                // 新增，查询到新的批次信息和旧的批次信息有差异需要更新
                

                // 有，赋值给工艺卡
                processcard = oldProcesscard;
            }*/


            LamInfo lamInfo = getProcessCardFromMes(processCardCode, userName);
            if (lamInfo.getStatus_code() == 200) {
                processcard = getProcesscard(lamInfo);
                Processcard oldProcesscard = processcardRepository.findByProcesscardCode(processCardCode);
                if (ObjectUtil.isEmpty(oldProcesscard)){
                    // 数据库中不存在该批次号信息
                    String layerName = processcard.getLayerName();
                    if (ObjectUtil.isEmpty(pressRecipesRepository.findByLamProgram(layerName))) {
                        log.error("没有找到压机资料，压机程式名称：{}", layerName);
                        mesMessage.setSuccessCode(400);
                        mesMessage.setErrorMessage("没有找到压机资料!");
                        return mesMessage;
                    }
                    processcardRepository.saveAndFlush(processcard);
                    processcard = processcardRepository.findByProcesscardCode(processCardCode);
                } else {
                    processcard = oldProcesscard;
                }
            } else {
                mesMessage.setSuccessCode(400);
                mesMessage.setErrorMessage("没有找到该批次号的信息");
                return mesMessage;
            }


            ProductionStation productionStation = productionStationRepository.findProductionStationByStationCode(stationCode);
            // 绑定工位和工艺卡
            productionStation.setProcesscardId(processcard.getId());
            productionStation.setUserName(userName);
            // 更新叠合区信息
            productionStationRepository.updateProductionStationById(processcard.getId(), userName, productionStation.getId());
            // 返回mesMessage包括工艺卡信息和叠合工艺图
            mesMessage.setSuccessCode(200);
            mesMessage.setProcesscard(processcard);
            return mesMessage;

        } catch (Exception e) {
            MesMessage mesMessage = new MesMessage();
            mesMessage.setSuccessCode(400);
            mesMessage.setErrorMessage("没有找到该批次号的信息,错误信息："+e.getMessage());
            return mesMessage;
        }
    }

    /**
     * 从MES获取工程信息
     * @param processCardCode 工艺卡编码
     * @param emp 作业员
     * @return 工程信息
     */
    public LamInfo getProcessCardFromMes(String processCardCode, String emp){

        String url = "http://172.24.153.61:8023/mach/MLPinLamHuiLiu/GetMassLamWorkOrderInfo?wo="
                .concat(processCardCode)
                .concat("&mach_code=")
                .concat("设备编码")
                .concat("&op_name=")
                .concat(emp);

        // 创建 RestTemplate 实例
        RestTemplate restTemplate = new RestTemplate();

        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.set("Content-Type", "application/json");

        // 创建请求实体
        HttpEntity<String> entity = new HttpEntity<>(headers);
        ResponseEntity<LamInfo> response = restTemplate.exchange(url, HttpMethod.GET, entity, LamInfo.class);
        log.info("通过工艺卡：{}获取工程信息: "+response.getBody(),processCardCode);
        return response.getBody();
    }

    /**
     * 人工扫描载盘后，通过登录用户名查询工作站，查询工位id获取工艺卡id，完成载盘和工艺卡的绑定
     * 人工扫描载盘后记录叠合工艺的开始时间
     * @param palletCode 载盘号
     * @param flowTo 流向
     * @param stationCode 工作站编码
     */
    @Transactional
    public void scanPalletCode(Integer flowTo, String palletCode,String stationCode){
        ProductionStation station = productionStationRepository.findProductionStationByStationCode(stationCode);

        // 根据载盘编码查询载盘
        Pallet pallet = palletRepository.findPalletByPalletCode(palletCode);
        // 没有查询到载盘信息,保存载盘信息到数据库
        if (ObjectUtil.isEmpty(pallet)){
            Pallet newPallet = new Pallet();
            newPallet.setPalletCode(palletCode);
            newPallet.setLayUpStationCode(stationCode);
            newPallet.setCreateTime(DateTime.now().toTimestamp());
            newPallet.setCreateBy(LoginUtil.getLoginUser());
            log.info("扫描到的新的载盘信息：{}", newPallet);
            try {
                palletRepository.saveAndFlush(newPallet);
                pallet = palletRepository.findPalletByPalletCode(palletCode);
                log.info("查找到数据库中新的载盘信息：{}",pallet);
            } catch (Exception e) {
                log.error("保存新载盘信息时出错，错误原因：{}错误载盘码：{}", e.getMessage(), palletCode);
            }
        }
        // 绑定载盘和工艺卡并设置流动方向
        palletRepository.bindingProcessCard(flowTo, station.getProcesscardId(), DateTime.now().toTimestamp(), LoginUtil.getLoginUser(), stationCode, pallet.getId());

        // 记录叠合工艺的开始时间
        ProductionInfo layUpProduction = new ProductionInfo();
        layUpProduction.setProductionType(1);
        layUpProduction.setPalletCode(pallet.getPalletCode());
        layUpProduction.setStationCode(stationCode);
        layUpProduction.setLayUpBy(LoginUtil.getLoginUser());
        // 工艺卡信息
        Processcard processcard = processcardRepository.findProcesscardById(station.getProcesscardId());
        layUpProduction.setWorkNum(processcard.getWorkNum());
        layUpProduction.setQty(processcard.getQty());
        layUpProduction.setMaterial(processcard.getMaterial());
        layUpProduction.setLayUpName(processcard.getLayerName());
        layUpProduction.setProductionStatus(1);
        layUpProduction.setLayUpStartTime(DateTime.now().toTimestamp());

        productionInfoRepository.save(layUpProduction);
/*

        // 在叠合完成后生成一条只有起点没有终点的入库任务，用于在入库口对比排除重复扫码重复生成任务的问题
        InBoundMission hasInBoundMission = inBoundMissionRepository.findInBoundMissionByPalletCode(palletCode);
        if (ObjectUtil.isEmpty(hasInBoundMission)){
            InBoundMission inBoundMission = new InBoundMission();
            inBoundMission.setMissionCode(UniqueCodeUtil.createCode());
            inBoundMission.setMissionStatus(1);
            inBoundMission.setPriority(0);
            inBoundMission.setPalletCode(palletCode);
            // String zoneCode = stationCode.substring(0, 1);
            inBoundMission.setSource("AInBound");
            inBoundMission.setCreateTime(DateTime.now().toTimestamp());
        switch (zoneCode){
            case "A": inBoundMission.setSource("AInBound");
            break;
            case "B": inBoundMission.setSource("AInBound");
            break;
        }
            inBoundMissionRepository.save(inBoundMission);
        }
*/
        // 告诉plc绑定完成信号
        log.info("工作站{}载盘绑定完成",stationCode);
        switch (stationCode){
            case "LayUp1-w1a":
                layUpTCP.writeWithRetry(RegisterAddressConfig.finishBindingPalletA,1,5);
                break;

            case "LayUp2-w1":
                layUpTCP.writeWithRetry(RegisterAddressConfig.finishBindingPalletB,1,5);
                break;

            case "LayUp3-w1c":
                noTwoLayUpTCP.writeWithRetry(RegisterAddressConfig.noTwoFinishBindingPalletA,1, 5);
                break;

            case "LayUp4-w1b":
                noTwoLayUpTCP.writeWithRetry(RegisterAddressConfig.noTwoFinishBindingPalletB,1, 5);
                break;

            case "LayUp5-w1e":
                noThreeLayUpTcp.writeWithRetry(RegisterAddressConfig.noThreeFinishBindingPalletA,1, 5);
                break;

            case "LayUp6-w1d":
                noThreeLayUpTcp.writeWithRetry(RegisterAddressConfig.noThreeFinishBindingPalletB,1, 5);
                break;
        }
        /*if (stationCode.equals("A121")){
            layUpTCP.write(RegisterAddressConfig.finishBindingPalletA,1);
        }else if(stationCode.equals("A122")){
            layUpTCP.write(RegisterAddressConfig.finishBindingPalletB,1);
        }*/


    }

    /**
     * 人工按照叠合图完成叠合，按启动按钮，校验载盘数据，数据校验通过，写入启动信号
     */
    @Transactional
    public void  finishLayUp(String palletCode){

        //先查找最新绑定的载盘
        ProductionInfo productionInfo = productionInfoRepository.findProductionInfosOrderByLayUpStartTime(palletCode).get(0);
        int id = productionInfo.getId();
        // 记录叠合工艺完成时间
        productionInfoRepository.updateProductionInfoLayUpFinishTime(new DateTime().toTimestamp(),id);

    }

    public Processcard getProcesscard(LamInfo lamInfo) {

        DecimalFormat df = new DecimalFormat("#.0");
        df.setRoundingMode(RoundingMode.FLOOR);

        Processcard processCard = new Processcard();
        processCard.setProcesscardCode(lamInfo.getWo());
        processCard.setWorkNum(lamInfo.getCp_rev());
        processCard.setProductType(lamInfo.getProduct_type());
        processCard.setMaterial(lamInfo.getMaterial());
        processCard.setThick(Double.valueOf(df.format(lamInfo.getBh()/25.4)));
        processCard.setSize1(Double.valueOf(df.format(lamInfo.getBc()/25.4)));
        processCard.setSize2(Double.valueOf(df.format(lamInfo.getBk()/25.4)));
        // 更新压合次数直接从mes系统获取
        int mlTime = lamInfo.getMlTime();
        processCard.setLayerName(lamInfo.getCp_rev().concat("_"+mlTime));
        return processCard;
    }

    // 强制结束生产
    // 当生产遇到信息错误或者物料不够等无法继续叠合作业时，人工可以点击结束生产来生产下一个工艺
    @Transactional
    public void forcefulFinish(String palletCode){

        // 删除这个载盘的工艺信息
        productionInfoRepository.deleteProductionInfoByPalletCodeAndProductionTypeAndProductionStatus(palletCode,1,1);

    }

    public String getLayerName(LamInfo lamInfo){
        String workNum = lamInfo.getCp_rev();
        String bom = lamInfo.getLayers().get(0).getBom();
        int layerNum = 0;
        switch (bom) {
            case "TOP" :
            case "ATOP" :
            /*case "OTOP" :
                layerNum=1;*/
                layerNum=1;
            break;

            case "BTOP" : layerNum=2;
            break;

            case "CTOP" : layerNum=3;
            break;

            case "DTOP" : layerNum=4;
            break;

            case "ETOP" : layerNum=5;
            break;

            case "FTOP" : layerNum=6;
            break;

            case "GTOP" : layerNum=7;
            break;

            case "HTOP" : layerNum=8;
            break;

            case "ITOP" : layerNum=9;
            break;

            case "JTOP" : layerNum=10;
            break;

            // 新增OTOP的判断
            case "OTOP" :

                // 拿到该工程号的所有批次号
                List<Processcard> processcardList = processcardRepository.findProcesscardsByWorkNum(workNum);

                // 拿到所有的压合层名
                List<String> lamupNames = processcardList.stream().map(Processcard::getLayerName).collect(Collectors.toList());

                // 找到最大的一个数字
                int maxNum = lamupNames.stream()
                        .map(num -> num.split("_")[1])
                        .mapToInt(Integer::parseInt)
                        .max()
                        .orElseThrow(() -> new IllegalStateException("没有找到最后一次压合次数"));

                // 获取批次号后缀
                List<String> result = processcardList.stream()
                        .map(Processcard::getProcesscardCode)   // 获取Processcard的processCard属性
                        .map(processCard -> {
                            int lastDashIndex = processCard.lastIndexOf("-");
                            return processCard.substring(lastDashIndex + 1);
                        })
                        .collect(Collectors.toList());

                // 判断是否已经存在后缀是"101"的批次号
                if (result.stream().anyMatch("101"::equals)){
                    layerNum = maxNum;
                } else {
                    layerNum = maxNum+1;
                }
                break;
        }
        return workNum.concat("_").concat(String.valueOf(layerNum));
    }
}
